package com.gis.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gis.dto.WaterQualityReportDTO;
import com.gis.dto.YearAndSeasonDTO;
import com.gis.entity.StationData;
import com.gis.exception.CustomException;
import com.gis.service.StationDataService;
import com.gis.utils.PythonUtil;
import jakarta.servlet.ServletOutputStream;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gis.entity.WaterQualityData;
import com.gis.mapper.WaterQualityDataMapper;
import com.gis.service.WaterQualityDataService;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static org.apache.commons.lang.StringUtils.capitalize;

@Slf4j
@Service
public class WaterQualityDataServiceImpl extends ServiceImpl<WaterQualityDataMapper, WaterQualityData> implements WaterQualityDataService{

    @Autowired
    private WaterQualityDataMapper waterQualityDataMapper;
    @Autowired
    private StationDataService stationDataService;
    @Value("${python.path}")
    private String pythonPath;
    @Autowired
    private PythonUtil pythonUtil;

    @Override
    public List<WaterQualityReportDTO> getWaterQualityAvgByYearAndSeason(int year, String season) {
        return waterQualityDataMapper.getWaterQualityAvgByYearAndSeason(year,season);
    }

    @Override
    public List<WaterQualityData> getRedtideDataByTime(int year, String season) {
        QueryWrapper<WaterQualityData> waterQualityDataWrapper = new QueryWrapper<WaterQualityData>()
                .eq("year", year)
                .eq("season", season)
                .groupBy("station_id")
                // todo 实际需要的字段
                .select("station_id, COALESCE(AVG(ph), -1.0) AS ph, " +
                        "COALESCE(AVG(dissolved_oxygen), -1.0) AS dissolved_oxygen");
        return waterQualityDataMapper.selectList(waterQualityDataWrapper);
    }


    @Override
    public List<WaterQualityData> getOilspillDataByTime(int year, String season) {
        QueryWrapper<WaterQualityData> waterQualityDataWrapper = new QueryWrapper<WaterQualityData>()
                .eq("year", year)
                .eq("season", season)
                .groupBy("station_id")
                // todo 实际需要的字段
                .select("station_id, COALESCE(AVG(petroleum_class), -1.0) AS petroleum_class");
        return waterQualityDataMapper.selectList(waterQualityDataWrapper);
    }

    public List<WaterQualityData> getAllByYearAndSeason(int year, String season, String tideStatus) {
        QueryWrapper<WaterQualityData> wrapper = new QueryWrapper<WaterQualityData>()
                .eq("year", year)
                .eq("season", season)
                .eq("tide_status", tideStatus);
        return waterQualityDataMapper.selectList(wrapper);
    }

    @Override
    public void generateTIF(ServletOutputStream outputStream, String param, int year, String season, String tideStatus) {
        List<WaterQualityData> waterQualityDataList = getAllByYearAndSeason(year, season, tideStatus);
        List<List<Float>> tripleList = new ArrayList<>();
        for(WaterQualityData waterQualityData : waterQualityDataList){
            String methodName = "get" + capitalize(param);
            Method method = null;
            try {
                method = WaterQualityData.class.getMethod(methodName);
                Float paramValue = (Float) method.invoke(waterQualityData);
                if(paramValue != null){
                    StationData stationData = stationDataService.getById(waterQualityData.getStationId());
                    List<Float> data= new ArrayList<>();
                    data.add(stationData.getLongitude());
                    data.add(stationData.getLatitude());
                    data.add(paramValue);
                    tripleList.add(data);
                }
            } catch (NoSuchMethodException e) {
                throw new CustomException("反射错误");
            } catch (InvocationTargetException e) {
                throw new CustomException("反射错误");
            } catch (IllegalAccessException e) {
                throw new CustomException("反射错误");
            }
        }
        if(tripleList.isEmpty()){
            log.info("无数据进行空间分析");
            throw new CustomException("无数据进行空间分析");
        }
        boolean success = pythonUtil.runSpatialAnalysis(tripleList);
        if(success){
            String tifPath = pythonPath + "/tif/output.tif";
            File file = new File(tifPath);
            try (FileInputStream fis = new FileInputStream(file);
                 BufferedInputStream bis = new BufferedInputStream(fis)) {
                byte[] bytes = new byte[(int) file.length()];
                int bytesRead = bis.read(bytes);
                if (bytesRead != -1) {
                    outputStream.write(bytes, 0, bytesRead);
                }
            } catch (IOException e) {
                throw new CustomException("文件读取或写入失败");
            }
        }else {
            throw new CustomException("空间分析失败");
        }
    }

    /**
     * 返回所有可以监测水质的站点id
     * @return
     */
    @Override
    public List<Integer> selectAllIds() {
        QueryWrapper<WaterQualityData> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("DISTINCT station_id");
        return waterQualityDataMapper.selectObjs(queryWrapper).stream()
                .map(obj -> (Integer) obj)
                .collect(Collectors.toList());
    }

    /**
     * 获取某个时间段内站点的监测数据
     * @param fromYear
     * @param fromSeason
     * @param toYear
     * @param toSeason
     * @param tideStatus
     * @return
     */
    @Override
    public List<WaterQualityData> getFromYearAndSeason(int stationId, int fromYear, String fromSeason, int toYear, String toSeason, String tideStatus) {
        List<WaterQualityData> waterQualityDataList = waterQualityDataMapper.getFromYear(stationId, fromYear, toYear, tideStatus);
        List<WaterQualityData> result = new ArrayList<>();
        for (WaterQualityData w : waterQualityDataList){
            if(w.getYear()==fromYear){
                if(fromSeason.equals("fall")&&w.getSeason().equals("spring")){
                    continue;
                }
            }
            if(w.getYear()==toYear){
                if(toSeason.equals("spring")&&w.getSeason().equals("fall")){
                    continue;
                }
            }
            result.add(w);
        }
        return result;
    }

    @Override
    public YearAndSeasonDTO getLatestYearAndSeason(int id) {
        WaterQualityData waterQualityData = waterQualityDataMapper.LatestYearAndSeason(id);
        YearAndSeasonDTO yearAndSeasonDTO = new YearAndSeasonDTO();
        BeanUtils.copyProperties(waterQualityData, yearAndSeasonDTO);
        return yearAndSeasonDTO;
    }

    /**
     * 获取某个参数的5个最新值
     * @param param
     * @param n
     * @param id
     * @return
     */
    @Override
    public List<Float> getParamLastN(String param, int n, int id) {
        List<Float> data = new ArrayList<>();
        List<WaterQualityData> waterQualityData = waterQualityDataMapper.getLastN(n, id);
        for(WaterQualityData w : waterQualityData){
            String methodName = "get" + capitalize(param);
            try {
                Method method = WaterQualityData.class.getMethod(methodName);
                Float result = (Float) method.invoke(w);
                data.add(result);
            } catch (NoSuchMethodException e) {
                throw new CustomException("反射错误");
            } catch (InvocationTargetException e) {
                throw new CustomException("反射错误");
            } catch (IllegalAccessException e) {
                throw new CustomException("反射错误");
            }
        }
        return data;
    }
}
